package com.olc.railing.http;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.olc.railing.BuildConfig;
import com.olc.railing.constant.Constants;
import com.olc.railing.utils.CommUtils;
import com.olc.railing.utils.MyLog;
import com.tyxh.paylibrary.exception.NetNotAvailableException;
import com.tyxh.paylibrary.exception.NullException;
import com.tyxh.paylibrary.listener.ResultCallBack;
import com.tyxh.paylibrary.model.MyExceptionType;
import com.tyxh.paylibrary.utils.ComonUtils;
import com.tyxh.paylibrary.utils.LogUtils;
import com.tyxh.paylibrary.utils.SharedUtils;
import com.tyxh.paylibrary.utils.SignUtils;


import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import io.etcext.config.SM2Config;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class HttpBusiness {
    private static final String TAG = HttpBusiness.class.getSimpleName();

    private static final String APP_KEY = "App-Key";
    private static final String AUTHORIZAON = "Authorization";

    private OkHttpClient okHttpClient;

    private static HttpBusiness mInstance;

    private HttpBusiness() {
        //添加cookie
        okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时间
                .readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间
                .writeTimeout(10,TimeUnit.SECONDS)
                .build();
    }

    /**
     * 单例模式创建OkHttpBusiness
     *
     * @return mInstance
     */
    public static HttpBusiness getInstance() {
        if (mInstance == null) {
            synchronized (HttpBusiness.class) {
                mInstance = new HttpBusiness();
            }
        }
        return mInstance;
    }


    /**
     * get 异步请求
     */
    public void get(Context context, String url, TreeMap<String, String> paramsMap, ResultCallBack callback) throws NetNotAvailableException, NullException {

        if (callback == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"callback is null");
        }
        if (paramsMap == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"paramsMap is null");
        }

        if (!ComonUtils.isNetworkConnected(context)) {
            throw new NetNotAvailableException(MyExceptionType.NO_NET.code,"Network can't use,ple check net");
        }


    /*    if (TextUtils.isEmpty(appkey)) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"appkey is null");
        }
*/

        String paramStr = getParams(paramsMap);
        String requestUrl = url + paramStr;
        //其中 'App‑key’由平台分发；‘Dev‑Tpye’如手持机设备填写’HandTerminal’
        //Dev‑Tpye’，App‑key’，‘Authorizaon’，
        deliveryLocalResult(callback, new Request.Builder()
                .header("Dev-Type", Constants.DEV_TYPE)
                .header(APP_KEY,  SharedUtils.getAppKey(context))
                .header(AUTHORIZAON, SignUtils.calculateSign(paramsMap))
                .url(requestUrl)
                .build());
    }

    /**
     * get 异步请求
     */
    public void downloadFile(Context context, String url, TreeMap<String, String> paramsMap,String fileName, ResultCallBack callback) throws NetNotAvailableException, NullException {

        if (callback == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"callback is null");
        }
        if (paramsMap == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"paramsMap is null");
        }

        if (!ComonUtils.isNetworkConnected(context)) {
            throw new NetNotAvailableException(MyExceptionType.NO_NET.code,"Network can't use,ple check net");
        }

/*
        String appkey = SharedUtils.getAppKey(context);
        if (TextUtils.isEmpty(appkey)) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"appkey is null");
        }*/


        String paramStr = getParams(paramsMap);
        String requestUrl = url + paramStr;
        //其中 'App‑key’由平台分发；‘Dev‑Tpye’如手持机设备填写’HandTerminal’
        //Dev‑Tpye’，App‑key’，‘Authorizaon’，
        deliveryApkResult(callback, fileName,new Request.Builder()
                .header("Dev-Type", Constants.DEV_TYPE)
                .header(APP_KEY,  SharedUtils.getAppKey(context))
                .header(AUTHORIZAON, SignUtils.calculateSign(paramsMap))
                .url(requestUrl)
                .build());
    }

    /**
     * post 异步请求
     */
    public void uploadFile(Context context, String url, TreeMap<String, String> params,String filePath,String fileName, ResultCallBack callback) throws NetNotAvailableException, NullException {
        if (callback == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"callback is null");
        }
        if (params == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"paramsMap is null");
        }

        if (!ComonUtils.isNetworkConnected(context)) {
            throw new NetNotAvailableException(MyExceptionType.NO_NET.code,"network can't use,ple check net");
        }
  /*      String appkey = SharedUtils.getAppKey(context);
        if (TextUtils.isEmpty(appkey)) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"appkey is null");
        }*/

        String authorizaon = SignUtils.calculateSign(params);
        String jsonStr = new Gson().toJson(params);
        MyLog.d(MyLog.TAG, "jsonStr = " + jsonStr);
        RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), new File(filePath+fileName));
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", fileName,fileBody)
                .addFormDataPart("dev_number",CommUtils.getDeviceSN())
                .addFormDataPart("file_name", fileName)
                .addFormDataPart("remark","")
                .build();
        deliveryLocalResult(callback, new Request.Builder()
                .header("Dev-Type",Constants.DEV_TYPE)
                .header(APP_KEY,  SharedUtils.getAppKey(context))
                .header(AUTHORIZAON, authorizaon)
                .url(url)
                .post(requestBody)
                .build());
    }



    /**
     * post 异步请求
     */
    public void post(Context context, String url, TreeMap<String, String> params, ResultCallBack callback) throws NetNotAvailableException, NullException {
        if (callback == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"callback is null");
        }
        if (params == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"paramsMap is null");
        }

        if (!ComonUtils.isNetworkConnected(context)) {
            throw new NetNotAvailableException(MyExceptionType.NO_NET.code,"network can't use,ple check net");
        }
/*        String appkey = SharedUtils.getAppKey(context);
        if (TextUtils.isEmpty(appkey)) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"appkey is null");
        }*/
        if(BuildConfig.isDebug){
            MyLog.d(MyLog.TAG,"appkey： "+ SharedUtils.getAppKey(context));
        }


        String authorizaon = SignUtils.calculateSign(params);
        String jsonStr = new Gson().toJson(params);
        MyLog.d(MyLog.TAG, "jsonStr = " + jsonStr);


        RequestBody body = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonStr);
        deliveryLocalResult(callback, new Request.Builder()
                .header("Dev-Type",Constants.DEV_TYPE)
                .header(APP_KEY,  SharedUtils.getAppKey(context))
                .header(AUTHORIZAON, authorizaon)
                .url(url)
                .post(body)
                .build());
    }

    /**
     * post 异步请求
     */
    public void post(Context context, String url, String requestData, ResultCallBack callback) throws NetNotAvailableException, NullException {
        if (callback == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"callback is null");
        }
        if (requestData == null) {
            throw new NullException(MyExceptionType.NULL_DATA.code,"requestData is null");
        }
        if (!ComonUtils.isNetworkConnected(context)) {
            throw new NetNotAvailableException(MyExceptionType.NO_NET.code,"network can't use,ple check net");
        }
        MyLog.d(MyLog.TAG, "url = " + url);
        MyLog.d(MyLog.TAG, "requestData = " + requestData);
        RequestBody body = RequestBody.create(requestData,MediaType.parse("text/plain; charset=utf-8"));
        deliveryResult(callback, new Request.Builder()
                .url(url)
                .post(body)
                .build());
    }

    @NotNull
    private String getParams(Map<String, String> paramsMap) {
        String paramStr = "";
        if (paramsMap != null) {
            StringBuilder tempParams = new StringBuilder();
            tempParams.append("?");
            int pos = 0;
            for (String key : paramsMap.keySet()) {
                if (pos > 0) {
                    tempParams.append("&");
                }
                try {
                    tempParams.append(String.format("%s=%s", key, URLEncoder.encode(paramsMap.get(key), "utf-8")));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                pos++;
            }
            paramStr = tempParams.toString();
        }
        return paramStr;
    }
    private boolean isfrist = false;//测试用的

    /**
     * 请求回调处理方法并传递返回值
     *R
     * @param callback Map类型请求参数
     * @param request  Request请求
     */
    private void deliveryResult(final ResultCallBack callback, final Request request) {
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException ioException) {
                MyLog.e(MyLog.TAG, "deliveryResult onFailure    " + ioException.toString());
                if(isfrist){
                   // isfrist = false;
                    try {
                        // MyLog.e(MyLog.TAG, "响应 resposeStr    " + resposeStr);
                        String resposeStr = "{\"code\":\"100\",\"msg\":\"请求成功\",\"data\":[{\"goodsId\":\"19164b5cc554426aa0c2330e2f4763c8\",\"goodsCode\":\"92\",\"payMoney\":21091,\"amount\":1,\"gunId\":\"577001054bbf4724af99cfb0fedd8384\",\"totalMoney\":21091,\"litter\":\"40.56\",\"unit\":\"L\",\"otherOrderId\":\"20211102115558bhbv1jbd1066645327\",\"goodsName\":\"国VI92#\",\"unitPrice\":520,\"goodsType\":1,\"sellingPrice\":21091}]}";
                        JSONObject jsonObject = new JSONObject(resposeStr);
                        CommonBackJson commonBackJson = new CommonBackJson();
                        commonBackJson.setCode(jsonObject.getString("code"));
                        commonBackJson.setMsg(jsonObject.getString("msg"));
                        commonBackJson.setData(jsonObject.getString("data"));
                        callback.onResponse(200, commonBackJson);
                    } catch (Exception jsonException) {
                        jsonException.printStackTrace();
                    }
                    return;
                }else{
                     callback.onFail(MyExceptionType.HTTP_EXCEPTION.code,ioException);
                }




            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    MyLog.d(MyLog.TAG, "请求url     " + response.request().url().toString() + " code: " + response.code());
                    String resposeStr = response.body().string();
                    if(!TextUtils.isEmpty(resposeStr)){
                        resposeStr = SM2Config.doDecrypt(resposeStr, Constants.PRIVATE_KEY);
                    }
                    MyLog.d(MyLog.TAG, "响应 resposeStr    " + resposeStr);
                    if (response.code() == 200) {
                        JSONObject jsonObject = new JSONObject(resposeStr);
                        CommonBackJson commonBackJson = new CommonBackJson();
                        commonBackJson.setCode(jsonObject.getString("code"));
                        commonBackJson.setMsg(jsonObject.getString("msg"));
                        commonBackJson.setData(jsonObject.getString("data"));
                        callback.onResponse(response.code(), commonBackJson);
                    } else {
                        callback.onHttpFail(response.code(), resposeStr);
                    }
                } catch (IOException ioException) {
                    callback.onFail(MyExceptionType.CODE_EXCEPTION.code,ioException);
                } catch (JSONException jsonException) {
                    callback.onFail(MyExceptionType.CODE_EXCEPTION.code,jsonException);
                }
            }
        });
    }



    /**
     * 请求回调处理方法并传递返回值
     *
     * @param callback Map类型请求参数
     * @param request  Request请求
     */
    private void deliveryLocalResult(final ResultCallBack callback, final Request request) {
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException ioException) {
                MyLog.e(MyLog.TAG, "deliveryLocalResult onFailure    " + ioException.toString());
                callback.onFail(MyExceptionType.HTTP_EXCEPTION.code,ioException);
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    MyLog.d(MyLog.TAG, "请求url     " + response.request().url().toString() + " code: " + response.code());
                    String resposeStr = response.body().string();
                    MyLog.d(MyLog.TAG, "响应 resposeStr    " + resposeStr);
                    if (response.code() == 200) {
                        JSONObject jsonObject = new JSONObject(resposeStr);
                        LocalCommonBackJson commonBackJson = new LocalCommonBackJson();
                        commonBackJson.setErr_code(jsonObject.getString("err_code"));
                        commonBackJson.setErr_msg(jsonObject.getString("err_msg"));
                        commonBackJson.setData(jsonObject.getString("data"));
                        callback.onResponse(response.code(), commonBackJson);
                    } else {
                        callback.onHttpFail(response.code(), resposeStr);
                    }
                } catch (IOException ioException) {
                    callback.onFail(MyExceptionType.CODE_EXCEPTION.code,ioException);
                } catch (JSONException jsonException) {
                    callback.onFail(MyExceptionType.CODE_EXCEPTION.code,jsonException);
                }
            }

        });
    }


    /**
     * 请求回调处理方法并传递返回值
     *
     * @param callback Map类型请求参数
     * @param request  Request请求
     */
    private void deliveryApkResult(final ResultCallBack callback, String fileName,final Request request) {
        final long startTime = System.currentTimeMillis();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException ioException) {
                callback.onFail(MyExceptionType.HTTP_EXCEPTION.code,ioException);
            }

            @Override
            public void onResponse(Call call, Response response) {
                if (response.code() == 200) {
                    LocalCommonBackJson commonBackJson = new LocalCommonBackJson();
                    InputStream is = null;
                    byte[] buf = new byte[2048];
                    int len = 0;
                    FileOutputStream fos = null;
                    // 储存下载文件的目录
                    File savePath = new File(Constants.FILE_PATH_INFO.get(Constants.FILE_PATH_DIR_APK));
                    if (!savePath.exists()) {
                        savePath.mkdir();
                    }
                    try {
                        is = response.body().byteStream();
                        long total = response.body().contentLength();
                        MyLog.e(MyLog.TAG,"download total : " + total);
                        File file = new File(savePath, fileName);
                        if(file.exists()){
                            file.delete();
                        }
                        fos = new FileOutputStream(file,true);
                        long sum = 0;
                        int progress = 0; ;
                        while ((len = is.read(buf,0,buf.length)) != -1) {
                            //MyLog.e(MyLog.TAG,"download len : " + len);
                            sum += len;
                            progress = (int) (sum * 1.0f / total * 100);
                          /*  if(BuildConfig.isDebug){
                                MyLog.e(MyLog.TAG,"download progress : " + progress +" sum: "+sum);
                            }*/
                            fos.write(buf, 0, len);
                            //  mView.onDownloading("",progress);
                        }
                        fos.flush();
                        MyLog.e(MyLog.TAG,"download success sum: "+sum);
                        MyLog.e(MyLog.TAG,"totalTime="+ ((System.currentTimeMillis() - startTime)/1000/60));
                        commonBackJson.setErr_code("0");
                        commonBackJson.setErr_msg(progress+"");
                        commonBackJson.setData(savePath.getAbsolutePath()+"/"+fileName);
                        callback.onResponse(response.code(), commonBackJson);
                    } catch (Exception e) {
                        e.printStackTrace();
                        MyLog.e(MyLog.TAG,"download failed : "+e.getMessage());
                    } finally {
                        try {
                            if (is != null)
                                is.close();
                            if (fos != null)
                                fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }


                } else {
                    callback.onHttpFail(response.code(), "fail");
                }


            }

        });
    }


}
